#pragma once
#include "common.h"

#define ENABLE_COUNTER 1
#if ENABLE_COUNTER

class Counter
{
private:
    uint64_t count = 0;
    static std::vector<Counter *> counters;

public:
    std::string name;
    Counter(const std::string name) : name(name)
    {
        counters.push_back(this);
    }
    ~Counter() {
        for(auto it = counters.begin(); it != counters.end(); it++) {
            if((*it) == this) {
                counters.erase(it);
                break;
            }
        }
    }
    inline uint64_t operator++()
    {
        count++;
        return count;
    }
    inline uint64_t operator++(int)
    {
        return count++;
    }

    inline operator uint64_t() const
    {
        return count;
    }
    inline Counter &operator=(const uint64_t &other)
    {
        count = other;
        return *this;
    }

    friend std::ostream &operator<<(std::ostream &os, const Counter &obj)
    {
        os << COLOR("[Counter] ",GREEN) << std::setw(24) << std::setfill(' ') << std::left << obj.name << std::right << ":\t" << std::to_string(obj.count);
        return os;
    }
    static void print_counters()
    {
        std::cout << "====================[Counters]====================\n";
        std::sort(counters.begin(), counters.end(), [](const Counter* a, const Counter* b) {
            return a->name < b->name;
        });
        for (auto counter : counters)
        {
            std::cout << *counter << std::endl;
        }
        std::cout << "==================================================\n";
    }
};
#else
class Counter
{
private:
    uint64_t count = 0;
    static std::vector<Counter *> counters;

public:
    std::string name;
    Counter(const std::string name) : name(name)
    {

    }
    inline uint64_t operator++()
    {
        return 0;
    }
    inline uint64_t operator++(int)
    {
        return 0;
    }

    inline operator uint64_t() const
    {
        return 0;
    }
    inline Counter &operator=(const uint64_t &other)
    {
        return *this;
    }

    friend std::ostream &operator<<(std::ostream &os, const Counter &obj)
    {
        return os;
    }
    static void print_counters()
    {
        std::cout << "====================[Counters]====================\n";
        std::sort(counters.begin(), counters.end(), [](const Counter* a, const Counter* b) {
            return a->name < b->name;
        });
        for (auto counter : counters)
        {
            std::cout << *counter << std::endl;
        }
        std::cout << "==================================================\n";
    }
};

#endif

uint64_t get_time_us();